#include <cmath>
#include <iostream>
#include <algorithm>
#include "decide.h"
#include "situation.h"
#include "parser.h"
#include "feature_extractor.h"

using namespace std;
using namespace stock_trade;

const unsigned int FEATURE_SIZE = 8;
const int MIN_NUMBER = 100;

const float QUANTITY_PERCENT_SCORE = 2000;
//const float QUANTITY_PERCENT_SCORE = 1000;
const float POWER_PERCENT_SCORE = 0;
//const float POWER_PERCENT_SCORE = 1500;
const float BASE_PRICE_UP_SCORE = 1500;
const float BASE_BIG_BUY_SCORE = 2000;
const float MUTIL_PRICE_BIG_BUY_SCORE = 50000;

const float STRONG_BUY_SCORE = 60000;

Transaction Decide::decide(const std::vector<float>& features, Stock stock, 
        Date date, Time time, float buyScore, float sellScore, Holder holder, float& score)
{
    Transaction transaction;
    if (features.size() != FEATURE_SIZE)
    {
        cerr << "bad feature length!" << endl;
        return transaction;
    }

    /*
     * ExtractorRecent3PriceFeature
     * ExtractorRecent3ActionFeature
     * ExtractorSituatuinFeature
     */
    score = 0;
    
    float rate = 1;
    if (features[7] > 1.5)
        rate = 1.5;
    if (features[7] > 2)
        rate = 2;
    
    if (features[0] > 0)
        score += features[0] / 7 * BASE_PRICE_UP_SCORE;
    else if (features[0] < 0)
        score -= features[0] / 7 * BASE_PRICE_UP_SCORE;

    if (features[1] > 0)
        score += features[1] / 7 * BASE_BIG_BUY_SCORE;
    else if (features[1] < 0)
        score -= features[1] / 7 * BASE_BIG_BUY_SCORE;

    if (features[0] > 0 && features[1] > 0)
        score += features[0] * features[1] / 49 * MUTIL_PRICE_BIG_BUY_SCORE * rate;
    if (features[0] < 0 && features[1] < 0)
        score -= features[0] * features[1] / 49 * MUTIL_PRICE_BIG_BUY_SCORE * rate;

    float quantityPercent = features[2];
    float powerPercent = features[3];

    if (quantityPercent > 1)
        score += quantityPercent * QUANTITY_PERCENT_SCORE;
    else if (quantityPercent < 1)
        score -= 1 / quantityPercent * QUANTITY_PERCENT_SCORE;

    if (powerPercent > 1)
        score += powerPercent * POWER_PERCENT_SCORE;
    else if (powerPercent < 1)
        score -= 1 / powerPercent * POWER_PERCENT_SCORE;

    if (score > buyScore)
        transaction.action = BUY;
    else if (score < sellScore)
        transaction.action = SELL;
    else
        transaction.action = NONE;

    if (quantityPercent == MAX_PERCENT && transaction.action == BUY 
     || quantityPercent == MIN_PERCENT && transaction.action == SELL)   //涨停不能买，跌停不能卖
        transaction.action = NONE;

    transaction.stock = stock;
    transaction.date = date;
    transaction.time = time;
    transaction.price = features[4];
    if (abs(transaction.price) < MIN_QUANTITY)
        transaction.action = NONE;
    //transaction.number = MAX_NUMBER;
    transaction.number = DecideNumber(features, transaction, holder, score, buyScore, sellScore);
    if (transaction.action != NONE)
        cout << "---- " << score << " " << transaction.ToString() << " XXX " << features[5] << " XXX " << features[6] << " YYY " << features[7] << endl;
    return transaction;
}

pair<vector<pair<Transaction, float> >, vector<pair<Transaction, float> > > Decide::decideAll(const vector<vector<float> >& allFeatures, const vector<Stock>& vecStock, Date date, Time time, float buyScore, float sellScore, Holder holder)
{
    vector<pair<Transaction, float> > vecBuyTransaction;
    vector<pair<Transaction, float> > vecSellTransaction;
    vector<pair<Transaction, float> > vecNoneTransaction;
    if (vecStock.size() != allFeatures.size())
    {
        cerr << "diff size from Stock and Features!" << endl;
        return make_pair(vecBuyTransaction, vecSellTransaction);
    }
    int length = allFeatures.size();
    for (int i = 0; i < length; i++)
    {
        float score = 0;
        Transaction t = decide(allFeatures[i], vecStock[i], date, time, buyScore, sellScore, holder, score);
        if (t.action == BUY)
            vecBuyTransaction.push_back(make_pair(t, score));
        else if (t.action == SELL)
            vecSellTransaction.push_back(make_pair(t, score));
        else        //NONE
            vecNoneTransaction.push_back(make_pair(t, score));
    }
    sort(vecBuyTransaction.begin(), vecBuyTransaction.end(), decrease);
    //如果有强买的单，就把不买入的单全卖了
    const float NONE_TO_SELL_SCORE = -5000;
    if (vecBuyTransaction.size() >= 1 && vecBuyTransaction[0].second > STRONG_BUY_SCORE)
    {
        for (int i = 0; i < vecNoneTransaction.size(); i++)
        {
            if (vecNoneTransaction[i].second < NONE_TO_SELL_SCORE && abs(vecNoneTransaction[i].first.price) > MIN_QUANTITY)
            {
                vecNoneTransaction[i].first.action = SELL;
                vecSellTransaction.push_back(vecNoneTransaction[i]);
            }
        }
        vecBuyTransaction[0].first.number = MAX_NUMBER;

    }
    sort(vecSellTransaction.begin(), vecSellTransaction.end(), increase);
    return make_pair(vecBuyTransaction, vecSellTransaction);
}

int Decide::DecideNumber(const vector<float>& features, const Transaction& transaction, const Holder& holder, float score, float buyScore, float sellScore)
{
    //return MAX_NUMBER;
    if (score > STRONG_BUY_SCORE)
        return MAX_NUMBER;
    if (transaction.action == NONE)
        return MAX_NUMBER;
    //by 凯利公式: f = (bp - q) / b = p - q/b
    //f: 此次投资占总资金的比例
    //p: 胜率
    //q: 败率 = 1 - p
    //b: 赔率
    //赔率按（最高价-当前价）/（当前价-最低价）来折算
    float maxPrice = features[5];
    float minPrice = features[6];
    if (abs(maxPrice + 1) < 0.00001 || abs(minPrice + 1) < 0.00001)
        return MAX_NUMBER;
    if (abs(maxPrice - 0) < 0.00001 || abs(minPrice - 0) < 0.00001 || abs(transaction.price - 0) < 0.00001)
        return MAX_NUMBER;
    float b = 1;
    if (transaction.action == BUY)
    {
        float f = 0.8;
        if (abs(transaction.price - minPrice) < 0.00001)
            return GetNumber(f * holder.validCash, transaction.price, MIN_NUMBER);
            //return MAX_NUMBER;
        //b = (maxPrice - transaction.price) / (transaction.price - minPrice);
        b = maxPrice / transaction.price / 2;
        if (b <= 1)
            b = 1;
        //score = buyScore ===> p = 0.5; score = 50000 ===> p = 1
        if (buyScore >= 50000)
            return GetNumber(f * holder.validCash, transaction.price, MIN_NUMBER);
            //return MAX_NUMBER;
        float p = 0.5 + (score - buyScore)/(50000 - buyScore) * 0.5;
        if (p >= 1)
            return GetNumber(f * holder.validCash, transaction.price, MIN_NUMBER);
            //return MAX_NUMBER;
        float q = 1 - p;
        f = p - q/b;
        if (f <= 0)
            return 0;
        if (f > 0.8)
            f = 0.8;
        float money = f * holder.validCash;
        return GetNumber(money, transaction.price, MIN_NUMBER);
    }
    if (transaction.action == SELL)
    {
        b = (transaction.price - minPrice) / (maxPrice - transaction.price);
        return MAX_NUMBER;
    }
}

int Decide::GetNumber(float money, float price, const int min_number)
{
    float number = money / price / (1 + Holder::fee);
    return int(number) - int(number) % min_number;
}

bool decrease(const pair<Transaction, float>& t1, const pair<Transaction, float>& t2)
{
    return t1.second > t2.second;
}

bool increase(const pair<Transaction, float>& t1, const pair<Transaction, float>& t2)
{
    return t1.second < t2.second;
}

vector<Transaction> Decide::decisionAll(vector<Stock> vecStock, Holder& holder, Date startDate, Date endDate, Time startTime, Time endTime, float buyScore, float sellScore)
{
    vector<Transaction> allTransaction;
    for (Date date = startDate; date <= endDate; ++date)
    {
        map<string, vector<Transaction> > mapTransaction;
        map<string, vector<Situation> > mapSituation;
        map<string, vector<Transaction> > mapLongTimeTransaction;
        map<string, vector<Situation> > mapLongTimeSituation;
        for (vector<Stock>::iterator i = vecStock.begin(); i != vecStock.end(); ++i)
        {
            vector<Transaction> vecTransaction = Parser::ParseTransaction(*i, date);
            vector<Situation> vecSituation = Parser::ParseSituation(*i, date);
            vector<Transaction> vecLongTimeTransaction = Parser::ParserLongTimeTransaction(*i, date, 2);
            vector<Situation> vecLongTimeSituation = Parser::ParserLongTimeSituation(*i, date, 7);
            mapTransaction[i->code] = vecTransaction;
            mapSituation[i->code] = vecSituation;
            mapLongTimeTransaction[i->code] = vecLongTimeTransaction;
            mapLongTimeSituation[i->code] = vecLongTimeSituation;
        }
        for (Time time = startTime; time <= endTime; ++time)
        {
            vector<vector<float> > allFeatures;
            for (vector<Stock>::iterator i = vecStock.begin(); i != vecStock.end(); ++i)
            {
                vector<float> features = FeatureExtractor::MergeFeature(mapSituation[i->code], mapTransaction[i->code], 
                                                                        mapLongTimeSituation[i->code], mapLongTimeTransaction[i->code], date, time);
                //cout << features[0] << "\t" << features[1] << "\t" << features[2] << "\t" << features[3] << endl;
                allFeatures.push_back(features);
            }

            pair<vector<pair<Transaction, float> >, vector<pair<Transaction, float> > > transactions = Decide::decideAll(allFeatures, vecStock, date, time, buyScore, sellScore, holder);
            for (vector<pair<Transaction, float> >::iterator i = transactions.first.begin(); i != transactions.first.end(); ++i)
            {
                bool returnValue = holder.processFix(i->first);
                if (returnValue && (i->first).number > 0)
                    allTransaction.push_back(i->first);
            }
            for (vector<pair<Transaction, float> >::iterator i = transactions.second.begin(); i != transactions.second.end(); ++i)
            {
                bool returnValue = holder.processFix(i->first);
                if (returnValue && (i->first).number > 0)
                    allTransaction.push_back(i->first);
            }
                //if (returnValue)
                //    cout << t.date << " " << t.time << " " << t.action 
                //        << " " << t.stock.name << " " << t.number << " " << t.price << endl;
        }
    }
    return allTransaction;
}

vector<Transaction> Decide::decisionAll(vector<Stock> vecStock, Holder& holder, Date date, Time time, float buyScore, float sellScore)
{
    vector<Transaction> allTransaction;
    for (vector<Stock>::iterator i = vecStock.begin(); i != vecStock.end(); ++i)
    {
        vector<Transaction> vecTransaction = Parser::ParseTransaction(*i, date);
        vector<Situation> vecSituation = Parser::ParseSituation(*i, date);
        vector<Transaction> vecLongTimeTransaction = Parser::ParserLongTimeTransaction(*i, date, 2);
        vector<Situation> vecLongTimeSituation = Parser::ParserLongTimeSituation(*i, date, 7);
        
        vector<vector<float> > allFeatures;
        vector<float> features = FeatureExtractor::MergeFeature(vecSituation, vecTransaction, vecLongTimeSituation, vecLongTimeTransaction, date, time);
        //cout << features[0] << "\t" << features[1] << "\t" << features[2] << "\t" << features[3] << endl;
        allFeatures.push_back(features);

        pair<vector<pair<Transaction, float> >, vector<pair<Transaction, float> > > transactions = Decide::decideAll(allFeatures, vecStock, date, time, buyScore, sellScore, holder);
        for (vector<pair<Transaction, float> >::iterator i = transactions.first.begin(); i != transactions.first.end(); ++i)
        {
            bool returnValue = holder.processFix(i->first);
            if (returnValue && (i->first).number > 0)
                allTransaction.push_back(i->first);
        }
        for (vector<pair<Transaction, float> >::iterator i = transactions.second.begin(); i != transactions.second.end(); ++i)
        {
            bool returnValue = holder.processFix(i->first);
            if (returnValue && (i->first).number > 0)
                allTransaction.push_back(i->first);
        }
            //if (returnValue)
            //    cout << t.date << " " << t.time << " " << t.action 
            //        << " " << t.stock.name << " " << t.number << " " << t.price << endl;
    }
    return allTransaction;
}

